module User::Notifiable
  extend ActiveSupport::Concern

  included do
    has_many :notifications, dependent: :destroy
    has_many :notification_bundles, class_name: "Notification::Bundle", dependent: :destroy

    generates_token_for :unsubscribe, expires_in: 1.month
  end

  def bundle(notification)
    with_lock do
      find_or_create_bundle_for(notification)
    end
  end

  private
    def find_or_create_bundle_for(notification)
      find_bundle_for(notification) || expand_pending_bundle_for(notification) || create_bundle_for(notification)
    end

    def find_bundle_for(notification)
      notification_bundles.pending.containing(notification).last
    end

    def expand_pending_bundle_for(notification)
      pending = notification_bundles.pending.last
      if pending.present? && notification.created_at < pending.starts_at
        pending.update!(starts_at: notification.created_at) # expand the window to include this notification
      end
    end

    def create_bundle_for(notification)
      notification_bundles.create!(starts_at: notification.created_at)
    end
end
